﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using VideoReflector.Models;
using VideoReflector.Views;
using EditableAdapter;

namespace VideoReflector.Controllers
{
    /// <summary>
    /// Controller tasked with editing application settings
    /// </summary>
    public class SettingsController : TaskController
    {
        #region Private fields

        // settings object being edited
        private ApplicationSettings _settings;
        // memento object to store original state of settings object to allow restore on cancel
        private Memento<ApplicationSettings> _settingsMemento;

        #endregion // Private fields

        #region Constructor

        /// <summary>
        /// Constructor for SettingsController
        /// </summary>
        /// <param name="settings"> ApplicationSettings object to be edited  </param>
        public SettingsController(ApplicationSettings settings)
        {
            _settings = settings;
            // store original state of settings to allow restore if necessary
            _settingsMemento = new Memento<ApplicationSettings>(settings);
        }
            
        #endregion // Constructor

        #region Public properties

        /// <summary>
        /// Public accessor of ApplicationSettings instance the controller is editing
        /// ApplicationSettings class is autogenerated from ApplicationSettings.xsd schema file
        /// and is generated with support for INotifyPropertyChanged so does not need to be wrapped
        /// for binding
        /// </summary>
        public ApplicationSettings Settings
        {
            get         { return _settings;  }
            private set { _settings = value; }
        }

        #endregion // Public properties

        #region Commands

        #region AddClipTagGroup

        private RelayCommand _addClipTagGroupCommand;

        /// <summary>
        /// Add a new clip tag group to the default clip tag group collection of the settings object
        /// </summary>
        public ICommand AddClipTagGroupCommand
        {
            get
            {
                if (_addClipTagGroupCommand == null)
                {
                    _addClipTagGroupCommand = new RelayCommand
                    (
                        param => this.AddClipTagGroup(),
                        param => this.CanAddClipTagGroup()
                    );
                }
                return _addClipTagGroupCommand;
            }
        }

        private void AddClipTagGroup()
        {
            if (Settings.DefaultClipTagGroups == null)
                Settings.DefaultClipTagGroups = new ObservableCollection<ClipTagGroup>();
            var tagGroup = new ClipTagGroup();
            tagGroup.ID = Settings.DefaultClipTagGroups.Count;
            tagGroup.Colour = "Blue";
            tagGroup.Symbol.Item = "QuestionSymbol";
            tagGroup.Symbol.ItemElementName = ItemChoiceType.DefaultSymbol;
            tagGroup.Label = "[Give me a label]";
            Settings.DefaultClipTagGroups.Add(tagGroup);
        }

        private bool CanAddClipTagGroup()
        {
            return Settings != null;
        }

        #endregion // AddClipTagGroup  
        
        #region RemoveClipTagGroup

        private RelayCommand _removeClipTagGroupCommand;

        /// <summary>
        /// Remove 
        /// </summary>
        public ICommand RemoveClipTagGroupCommand
        {
            get
            {
                if (_removeClipTagGroupCommand == null)
                {
                    _removeClipTagGroupCommand = new RelayCommand
                    (
                        param => this.RemoveClipTagGroup(),
                        param => this.CanRemoveClipTagGroup()
                    );
                }
                return _removeClipTagGroupCommand;
            }
        }

        private void RemoveClipTagGroup()
        {
            // get default collection view - allows abstract access to current (e.g. selected) item
            var tagGroupsView = CollectionViewSource.GetDefaultView(Settings.DefaultClipTagGroups);
            // remove current item from default groups if not null
            if (tagGroupsView != null && tagGroupsView.CurrentItem != null 
                && Settings.DefaultClipTagGroups.Contains(tagGroupsView.CurrentItem))
                Settings.DefaultClipTagGroups.Remove((ClipTagGroup) tagGroupsView.CurrentItem);
        }

        private bool CanRemoveClipTagGroup()
        {
            return Settings != null && Settings.DefaultClipTagGroups != null;
        }

        #endregion // RemoveClipTagGroup  
                
        #region BrowseForDefaultSaveDirectory

        private RelayCommand _browseForDefaultSaveDirectoryCommand;

        /// <summary>
        /// Create and display a folder browser dialog to select the default base directory to save
        /// session files to (within a time-stamped sub-directory)
        /// </summary>
        public ICommand BrowseForDefaultSaveDirectoryCommand
        {
            get
            {
                if (_browseForDefaultSaveDirectoryCommand == null)
                {
                    _browseForDefaultSaveDirectoryCommand = new RelayCommand
                    (
                        param => this.BrowseForDefaultSaveDirectory(),
                        param => this.CanBrowseForDefaultSaveDirectory()
                    );
                }
                return _browseForDefaultSaveDirectoryCommand;
            }
        }

        private void BrowseForDefaultSaveDirectory()
        {
            var dialog = new FolderPickerLib.FolderPickerDialog();
            dialog.Title = "Default Save Directory";
            dialog.InitialPath = Settings.ExpandedDefaultSaveDirectory;
            if (dialog.ShowDialog() == true)
            {
                Settings.DefaultSaveDirectory = dialog.SelectedPath;
            }
        }

        private bool CanBrowseForDefaultSaveDirectory()
        {
            return Settings != null;
        }

        #endregion // BrowseForDefaultSaveDirectory     
        
        #region OkSettings

        private RelayCommand _okSettingsCommand;

        /// <summary>
        /// Finish editing settings and save settings object to file
        /// </summary>
        public ICommand OkSettingsCommand
        {
            get
            {
                if (_okSettingsCommand == null)
                {
                    _okSettingsCommand = new RelayCommand
                    (
                        param => this.OkSettings(),
                        param => this.CanOkSettings()
                    );
                }
                return _okSettingsCommand;
            }
        }

        private void OkSettings()
        {
            // try write settings to file
            Exception e;
            Settings.SaveToFile("Settings.xml", Encoding.UTF8, out e);
            if (e != null)
            {
                MessageBox.Show("Error when trying to save settings file: " + e.Message, 
                    "Save Settings Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            OnFinished(new TaskFinishedEventArgs(false));
        }

        private bool CanOkSettings()
        {
            return Settings != null;
        }

        #endregion // OkSettings
        
        #region CancelSettings

        private RelayCommand _cancelSettingsCommand;

        /// <summary>
        /// Rollback settings object to state on controller construction
        /// </summary>
        public ICommand CancelSettingsCommand
        {
            get
            {
                if (_cancelSettingsCommand == null)
                {
                    _cancelSettingsCommand = new RelayCommand
                    (
                        param => this.CancelSettings(),
                        param => this.CanCancelSettings()
                    );
                }
                return _cancelSettingsCommand;
            }
        }

        private void CancelSettings()
        {
            // restore original settings state
            _settingsMemento.Restore(_settings);
            OnFinished(new TaskFinishedEventArgs(true));
        }

        private bool CanCancelSettings()
        {
            return true;
        }

        #endregion // CancelSettings  
                       
        #endregion // Commands
    }
}
